package flib;

import java.awt.geom.Line2D;
import java.util.Vector;

import processing.core.PGraphics;

import simpleGeom.Bounds2D;
import simpleGeom.Bounds3D;
import simpleGeom.Vec3D;

import simpleGeom.HasBounds3D;
import simpleGeom.Vec2D;

public class CopyOfGroup implements HasBounds3D{
	public Vector<FlibHENode> nodes = new Vector<FlibHENode>();
	public Vector<FlibWall> walls = new Vector<FlibWall>();
	public Vector<Room> rooms = new Vector<Room>();
	public CopyOfGroup parent;
	public Vector<CopyOfGroup>children;
	
public int nGroups=0;
public 	int nBuildings=0;
public	int nLevels;

public void display2D(PGraphics g2d){
		for (int i=0;i<rooms.size();i++){
			Room room=rooms.get(i);
			if (room.ispublic){
				//g2d.fill(200,0,0);
			}
			else{
				//g2d.fill(100,0,0);
			}
			if (room.isCold()){
				//g2d.fill(100,100,255);
			}
			room.display(g2d);
		}
		//g2d.stroke(255,0,0);
		for (int i=0;i<walls.size();i++){
			FlibWall wall=walls.get(i);
			wall.display2D(g2d);
		}
	}
	public FlibWall addWall(float x1, float y1, float x2, float y2, float tolerance) {
		FlibHENode n1 = addNode(x1, y1, tolerance);
		FlibHENode n2 = addNode(x2, y2, tolerance);
		FlibWall wall = new FlibWall(n1, n2);
		walls.add(wall);
		return wall;
	}

	public FlibHENode addNode(float x, float y, float tolerance) {
		for (int i = 0; i < nodes.size(); i++) {
			FlibHENode node = nodes.get(i);
			if (node.dist(x, y) <= tolerance)
				return node;
		}
		FlibHENode newNode = new FlibHENode(x, y);
		nodes.add(newNode);
		return newNode;
	}

	public Vector<FlibWall> getWallsByType(String type) {
		Vector<FlibWall> typeWalls = new Vector<FlibWall>();
		for (int i = 0; i < walls.size(); i++) {
			FlibWall wall = walls.get(i);
			WallType walltype = wall.type;
			if (walltype != null) {
				if (type.equals(wall.type.label)) {
					typeWalls.add(wall);
				}
			}
		}
		return typeWalls;
	}

	public void replaceWall(FlibWall wall, float tol) {
		replaceNode(wall.getN1(), tol);
		replaceNode(wall.getN2(), tol);
		for (int i = 0; i < walls.size(); i++) {
			FlibWall cwall = walls.get(i);
			if ((cwall.getN1() == wall.getN1() && cwall.getN2() == wall.getN2())
					|| (cwall.getN2() == wall.getN1() && cwall.getN1() == wall
							.getN2())) {
				walls.set(i, wall);
			}
		}
	}

	public void replaceNode(FlibHENode node, float tol) {

		boolean inside = false;
		for (int i = 0; i < nodes.size(); i++) {
			FlibHENode cNode = nodes.get(i);
			if (cNode.dist(node.x, node.y) < tol) {
				nodes.set(i, node);
				inside = true;
			}
		}
		if (!inside) {
			nodes.add(node);
		}
		for (int i = 0; i < walls.size(); i++) {
			FlibWall wall = walls.get(i);
			if (Vec2D.dist(wall.getN1(), node) < tol) {
				wall.hEdge.setOrg(node);
			}
			if (Vec2D.dist(wall.getN2(), node) < tol) {
				wall.hEdge.setDest(node);
			}
		}
	}

	public boolean contains2D(float x1, float y1, float x2, float y2,
			float tolerance) {
		int hits = 0;
		for (int i = 0; i < nodes.size(); i++) {
			FlibHENode p = nodes.get(i);
			if (p.dist(x1, y1) < tolerance) {
				hits++;
			}
			if (p.dist(x2, y2) < tolerance) {
				hits++;
			}
		}
		if (hits > 1)
			return true;
		return false;
	}

	public FlibHENode containsNode2D(float x, float y, Vector<FlibHENode> nodes,
			float tolerance) {
		for (int i = 0; i < nodes.size(); i++) {
			FlibHENode node = nodes.get(i);
			if (Vec2D.dist(node.x, node.y, x, y) <= tolerance)
				return node;
		}
		return null;
	}

	public Bounds3D getBounds3D() {
		// TODO Auto-generated method stub
		Bounds3D b3d=new Bounds3D();
		b3d.addAll(nodes);
		return b3d;
	}
	public Bounds2D getBounds2D() {
		// TODO Auto-generated method stub
		Bounds2D b2d=new Bounds2D();
		b2d.addAll(nodes);
		return b2d;
	}
	public void attach(){
		for (int i = 0; i < walls.size(); i++) {
			FlibWall wall = walls.get(i);
			wall.hEdge.attach();
		}
	}
	public void createRooms() {
		rooms = new Vector<Room>();
		
		for (int i = 0; i < walls.size(); i++) {
			FlibWall wall = walls.get(i);
			FlibHEdge hEdge = wall.hEdge;
			if (hEdge.getFace() == null) {
				addRoom(hEdge);
			}
			if (hEdge.getSym().getFace() == null) {
				addRoom(hEdge.getSym());
			}
		}
		Vector<Room>negativeRooms=new Vector<Room>();
		Vector<Room>positiveRooms=new Vector<Room>();

		
		for (int i = 0; i < rooms.size(); i++) {
			Room room = rooms.get(i);
			float cArea=room.getArea2D();
			if (cArea <= 0.001) {
				negativeRooms.add(room);				
			}
			else{
				positiveRooms.add(room);
			}
		}
		Vector<Room>negativeInnerRooms=new Vector<Room>();
		Vector<Room>negativeOuterRooms=new Vector<Room>();
		for (int i=0;i<negativeRooms.size();i++){
			Room r=negativeRooms.get(i);
			boolean isInside=false;
			for (int j=0;j<negativeRooms.size();j++){
				Room r2=negativeRooms.get(j);
				if (r!=r2&&r2.contains(r.getHEdge().x1(),r.getHEdge().y1())){
					negativeInnerRooms.add(r);
					isInside=true;
					break;
				}
				if (!isInside){
					negativeOuterRooms.add(r);
				}
			}
		}
		System.out.println("positiveRooms.size()"+positiveRooms.size());
		System.out.println("negativeOuterRooms.size(): "+negativeOuterRooms.size());
		System.out.println("negativeInnerRooms.size(): "+negativeInnerRooms.size());
		negativeRooms=negativeInnerRooms;
		for (int i=0;i<negativeOuterRooms.size();i++){
			Room r=negativeOuterRooms.get(i);
			removeRoom(r);
		}
		for (int i = 0; i < negativeRooms.size(); i++) {
			Room room = negativeRooms.get(i);
			Vec3D pt = room.getHEdge().getOrg();
			for (int j = 0; j < positiveRooms.size(); j++) {
				Room room2 = positiveRooms.get(j);
				if (room2.contains(pt.x, pt.y)) {
					System.out.println("innerWall");
					rooms.remove(room);
					negativeRooms.remove(room);
					makeInvisibleWall(room, room2);
					i--;
					j = positiveRooms.size();
					break;
				}
			}

		}
	}
	// makeInvisibleWall
	public void makeInvisibleWall(Room inner,Room outer){
		// find highest point from innerWall
		// find closest Point to this point, where there is no intersection between wall and wall
		FlibHENode highestPt=null;
		FlibHEdge hEdge=inner.hEdge;
		do {
			if (highestPt==null||hEdge.getY1()>highestPt.y){
				highestPt=hEdge.getOrg();
			}
			hEdge=hEdge.getNext();
		}while (hEdge!=inner.hEdge);
		
		
		
		FlibHENode closestPt=null;
		hEdge=outer.hEdge;
		float minDist=100000;
		
		do {
			if (closestPt==null||
					(hEdge.getY1()>highestPt.getY()&&highestPt.dist(hEdge.getOrg())<minDist)){
				minDist=highestPt.dist(hEdge.getOrg());
				closestPt=hEdge.getOrg();
			}
			hEdge=hEdge.getNext();
		}while (hEdge!=outer.hEdge);
		inner.detach();
		outer.detach();
		
		FlibWall wall = new FlibWall(highestPt,closestPt);
		wall.type = WallType.typeWallHelp;
		wall.hEdge.attach();
		wall.checked=true;
		wall.test=true;
		walls.add(wall);
		outer.attach(wall.hEdge);
		
	}
	
	public void removeRoom(Room room) {
		room.detach();
		rooms.remove(room);
	}
	public Room addRoom(FlibHEdge hEdge) {
		Room room = new Room();
		rooms.add(room);
		room.attach(hEdge);
		return room;
	}

	public void intersect() {
		for (int j = 0; j < walls.size(); j++) {
			FlibWall w = walls.get(j);
			w.checked=false;
		}
		for (int j = 0; j < walls.size() ; j++) {
			FlibWall w = walls.get(j);
			if (w.hEdge.getLength()<0.01f){
				walls.remove(w);
				w.hEdge.detach();
				j--;
			}
		}
		Vector<FlibWall> nextWalls = new Vector<FlibWall>(walls);
		
		while (nextWalls.size() > 0) {
			Vector<FlibWall> candidates = new Vector<FlibWall>();
			for (int j = 0; j < nextWalls.size(); j++) {
				FlibWall w = nextWalls.get(j);
				Line2D l = w.getLine2D();
				for (int jj = 0; jj < nodes.size(); jj++) {
					FlibHENode n = nodes.get(jj);
					if (n != w.getNode1() && n != w.getNode2()) {
						if (l.ptSegDist(n.getX(), n.getY()) < 0.01f) {
							boolean rem = walls.remove(w);
							FlibWall w1 = new FlibWall(w.getNode1(), n);
							FlibWall w2 = new FlibWall(n, w.getNode2());
							w1.type = w.type;
							w2.type = w.type;
							walls.add(w1);
							walls.add(w2);
							candidates.add(w1);
							candidates.add(w2);
							jj = nodes.size();
						}
					}
				}
			}
			nextWalls = candidates;
		}
		
		
		for (int j = 0; j < walls.size() - 1; j++) {
			FlibWall w1 = walls.get(j);

			for (int jj = j + 1; jj < walls.size(); jj++) {
				FlibWall w2 = walls.get(jj);
				if (!w1.checked && !w2.checked) {
					if (w1.getNode1() != w2.getNode1()
							&& w1.getNode1() != w2.getNode2()) {
						if (w1.getNode2() != w2.getNode1()
								&& w2.getNode1() != w2.getNode2()) {
							Line2D l1 = w1.getLine2D();
							Line2D l2 = w2.getLine2D();
							Vec2D p = Vec2D.segmentSegmentIntersection(
									l1.getP1(), l1.getP2(), l2.getP1(),
									l2.getP2());

							if (p != null) {
								FlibHENode n = new FlibHENode(p.getX(), p.getY());
								nodes.add(n);
								w1.checked = true;
								w2.checked = true;
								FlibWall w11 = new FlibWall(w1.getNode1(), n);
								w11.type = w1.type;
								walls.add(w11);
								FlibWall w12 = new FlibWall(n, w1.getNode2());
								w12.type = w1.type;
								walls.add(w12);
								FlibWall w21 = new FlibWall(w2.getNode1(), n);
								w21.type = w2.type;
								walls.add(w21);
								FlibWall w22 = new FlibWall(n, w2.getNode2());
								w22.type = w2.type;
								walls.add(w22);
							}
						}
					}
				}

			}
		}
		Vector<FlibWall> newWalls = new Vector<FlibWall>();
		for (int j = 0; j < walls.size(); j++) {
			FlibWall wall = walls.get(j);
			if (!wall.checked) {
				newWalls.add(wall);
			}
		}
		walls = newWalls;
	}
	public void translate(float x,float y){
		for (int i=0;i<nodes.size();i++){
			FlibHENode node=nodes.get(i);
			node.x+=x;
			node.y+=y;
		}
	}
	public void assignGroups(){
		
		for (int i=0;i<rooms.size();i++){
			Room room=rooms.get(i);
			room.groupId=-1;
		}
		int cId=0;
		for (int i=0;i<rooms.size();i++){
			Room room=rooms.get(i);
			if (room.groupId<0){
				room.groupId=cId;
				Vector<Room>candidates=new Vector<Room>();
				candidates.add(room);
				while (candidates.size()>0){
					Vector<Room>nextCandidates=new Vector<Room>();
					for (int j=0;j<candidates.size();j++){
						Room r=candidates.get(j);
						FlibHEdge hE=r.getHEdge();
						do{
							FlibHEData data=(FlibHEData) hE.getData();
							if (data.wall.isPermeable()){
								Room nb=(Room) hE.getSym().getFace();
								if (nb!=null&&nb.groupId<0&&nb.isPublic()==room.isPublic()){
									nb.groupId=cId;
									nextCandidates.add(nb);
								}
							}
							hE=hE.getNext();
							
						}while(hE!=r.getHEdge());
					}
					candidates=nextCandidates;
				}
				cId++;
			}
		}
		nGroups=cId;
	}
	public void assignBuildings(){
		
		for (int i=0;i<rooms.size();i++){
			Room room=rooms.get(i);
			room.buildingId=-1;
		}
		for (int i=0;i<nodes.size();i++){
			FlibHENode node=nodes.get(i);
			node.buildingId=-1;
		}
		int cId=0;
		for (int i=0;i<rooms.size();i++){
			Room room=rooms.get(i);
			if (room.buildingId<0&&room.getFaceNodes().size()>2){
				room.buildingId=cId;
				Vector<Room>candidates=new Vector<Room>();
				candidates.add(room);
				while (candidates.size()>0){
					Vector<Room>nextCandidates=new Vector<Room>();
					for (int j=0;j<candidates.size();j++){
						Room r=candidates.get(j);
						FlibHEdge hE=r.getHEdge();
						do{
							FlibHEData data=(FlibHEData) hE.getData();
								Room nb=(Room) hE.getSym().getFace();
								if (nb!=null&&nb!=r&&nb.buildingId<0){
									nb.buildingId=cId;
									nextCandidates.add(nb);
								}
							
							hE=hE.getNext();
							
						}while(hE!=r.getHEdge());
					}
					candidates=nextCandidates;
				}
				Vector<FlibHENode>candidatesN=new Vector<FlibHENode>();
				FlibHENode startNode=room.getHEdge().getOrg();
				startNode.buildingId=cId;
				candidatesN.add(startNode);
				while (candidatesN.size()>0){
					Vector<FlibHENode>nextCandidates=new Vector<FlibHENode>();
					for (int j=0;j<candidatesN.size();j++){
						FlibHENode r=candidatesN.get(j);
						Vector<FlibHENode>nbs=r.getNbs();
						for (int jj=0;jj<nbs.size();jj++){
							FlibHENode nb=nbs.get(jj);
							if (nb.buildingId<0){
							nextCandidates.add(nb);
							nb.buildingId=cId;
							}
						}
						
					}
					candidatesN=nextCandidates;
				}
				
				for (int j=0;j<nodes.size();j++){
					FlibHENode n=nodes.get(j);
					if (n.buildingId==cId){
						Vector<FlibHEdge>hEdges=n.getHEdges();
						for (int jj=0;jj<hEdges.size();jj++){
							FlibHEdge hEdge=hEdges.get(jj);
							FlibWall wall=((FlibHEData)hEdge.getData()).wall ;
							wall.buildingId=cId;
						}
					}
				}
				
				
				cId++;
			}
		}
		nBuildings=cId;
	}
	public void assignLevels(){
		for (int i=0;i<rooms.size();i++){
			Room room=rooms.get(i);
			room.levelId=-1;
		}
		int cId=0;
		for (int i=0;i<rooms.size();i++){
			Room room=rooms.get(i);
			if (room.levelId<0){
				room.levelId=cId;
				Vector<Room>candidates=new Vector<Room>();
				candidates.add(room);
				while (candidates.size()>0){
					Vector<Room>nextCandidates=new Vector<Room>();
					for (int j=0;j<candidates.size();j++){
						Room r=candidates.get(j);
						FlibHEdge hE=r.getHEdge();
						do{
							FlibHEData data=(FlibHEData) hE.getData();
								Room nb=(Room) hE.getSym().getFace();
								if (nb!=null&&nb.levelId<0){
									nb.levelId=cId;
									nextCandidates.add(nb);
								}
							
							hE=hE.getNext();
							
						}while(hE!=r.getHEdge());
					}
					candidates=nextCandidates;
				}
				cId++;
			}
		}
		nLevels=cId;
	}
}
